/*
* Author	: sgxiao
* Date		: Tue Fab 24 23:04:21 CST 2009
* version	: 0.4
* history	:
*	sgxiao	0.4	changing the algorithm of caculating the entry price
*	sgxiao	0.3	changing the filename for module SBO
*	sgxiao	0.2	changing the caculating according to the right price
*	sgxiao	0.1 changing the caculating days from 0 ~ n-1  to 1 ~ n
*/

import java.io.*;
import java.util.*;

public class SimpleBreakOut {
	public static Vector<String> dates = new Vector();
	public static Vector<String> tickers = new Vector();
	public static Vector<Double> openPrice = new Vector();
	public static Vector<Double> highPrice = new Vector();
	public static Vector<Double> lowPrice = new Vector();	
	public static Vector<Double> closePrice = new Vector();	
	public static Vector<Double> rightPrice = new Vector();
	public static Vector<Double> turnVolume = new Vector();
	public static Vector<Double> marketCap = new Vector();
	
	public static Vector<Double> SL = new Vector();
	public static Vector<Double> TR = new Vector();
	public static Vector<Double> ATR = new Vector();
	public static Vector<Double> max = new Vector();
	public static Vector<Double> min = new Vector();


	public static Double previousDayMax(int days, Vector<Double> vector, int currentPosition) {
		if( currentPosition - days < 0 ) return 0.0;
		
		int beginPosition = currentPosition - days;
		Double max = 0.0;
		for( ; beginPosition < currentPosition; beginPosition++) {
				if( max < vector.get(beginPosition) ) max = vector.get(beginPosition);
		}
		return max;
	}

	public static Double previousDayMin(int days, Vector<Double> vector, int currentPosition) {
		if( currentPosition - days < 0 ) return 0.0;
		
		int beginPosition = currentPosition - days;
		Double min = 9999999999999999.0;
		for( ; beginPosition < currentPosition; beginPosition++) {
				if( min > vector.get(beginPosition) ) min = vector.get(beginPosition);
		}
		return min;
	}
	
	public static Double trueRange(int position, double lastDayClosePrice) {
		double max[] = new double[3];
		max[0] = highPrice.get(position) - lowPrice.get(position);
		max[1] = highPrice.get(position) - lastDayClosePrice;
		max[2] = lastDayClosePrice - lowPrice.get(position);
		
		double max1 = 0.0;
		for( int i = 0; i < max.length; i++) {
			if( max[i] > max1 ) max1 = max[i];
		}
		
		return max1;
	}
	
	
	public final static int AVERAGE_TRUE_RANGE = 14;
	
	public static Double averageTrueRange(int position) {
		if ( position < AVERAGE_TRUE_RANGE ) return 0.0;
		
		double total = 0.0;
		for( int i = position - AVERAGE_TRUE_RANGE; i < position; i++ ) {
			total += TR.get(i);
		}
		
		return (total / AVERAGE_TRUE_RANGE);
	}

	public static void main(String[] args) throws IOException {
		if (args[0].equals("") || args[1].equals("")) {
			System.out.println("usage:\tSimpleBreakOut filename \n\tnumber[20|50|100|200]\n");
			System.exit(1);
		}
		
		Scanner scanner = new Scanner(new File(args[0]));
		int days = Integer.valueOf(args[1]);
		
		

		
		while(scanner.hasNext()) {
			dates.add(scanner.next());
			tickers.add(scanner.next());
			openPrice.add(scanner.nextDouble());
			highPrice.add(scanner.nextDouble());
			lowPrice.add(scanner.nextDouble());
			closePrice.add(scanner.nextDouble());
			rightPrice.add(scanner.nextDouble());
			turnVolume.add(scanner.nextDouble());
			marketCap.add(scanner.nextDouble());
			
			//TR.add( trueRange(i, lastDayClosePrice) );
			//ATR.add( averageTrueRange(i, lastDayClosePrice) );
			SL.add(0.0);
			TR.add(0.0);
			ATR.add(0.0);
			max.add(0.0);
			min.add(0.0);
		}
		
		
		int i = 0;
		while( i < tickers.size()) {

			max.set(i, previousDayMax(days, highPrice, i));
			min.set(i, previousDayMin(days / 2, lowPrice, i));
			//System.out.println(min.get(i) + "\t" + max.get(i));
			i++;
		}

		i = 0;
		double lastDayClosePrice = 0.0;
		boolean lastIsEntry = false;
		boolean isEntry = false;
		//boolean canShow = false;
		boolean canShowEntryPrice = false;
		boolean canShowExitPrce = false;
		boolean canShowReturnRate = false;
		
		
		double entryPrice = 0.0;
		double exitPrice = 0.0;
		
		double stopLossPrice =0.0;
		
		double returnRate = 0.0;
		
		
		/**/
		while( i < tickers.size()) {
			boolean isSingleDayTrade = false;
			
			TR.set(i, trueRange(i, lastDayClosePrice) );
			ATR.set(i, averageTrueRange(i) );	
			
			if(!isEntry && i >= days) {
				// 1） 检查 当天最高复权价> 前x-day 最高复权价。 这个判断，就只是在最前面的那行 
				//2） 如果是， 计算当天和连续true每天的SL= entry price - 2x average TR 然后以下的每一天都要检查 exit 的两个条件是否有达到 
				if( highPrice.get(i) > max.get(i) ) {
					///**System.out.println("if true");
				
					if (openPrice.get(i) < max.get(i)) {
						entryPrice = max.get(i) + 0.01;
					} else {
						entryPrice = openPrice.get(i);
					}
					stopLossPrice = entryPrice - averageTrueRange(i) * 2;
					//returnRate = entryPrice / closePrice.get(i) - 1;
					SL.set(i, stopLossPrice);
					//canShowEntryPrice = true;
					isEntry = true;
					
					if( lowPrice.get(i) <= SL.get(i) ) {
						if( closePrice.get(i) < SL.get(i) ) {
							///**/System.out.println("first exit1");
							///**/System.out.println("exitPrice: " + exitPrice + "\nentryPrice: " + entryPrice + "\nreturnRate: " + returnRate);
							exitPrice = SL.get(i) - 0.01;
							

							returnRate = exitPrice / entryPrice - 1.0;
							///**/System.out.println("exitPrice: " + exitPrice + "\nentryPrice: " + entryPrice + "\nreturnRate: " + returnRate);
							
							isSingleDayTrade = true;
							isEntry = false;
						}
					} else 
					
					if(lowPrice.get(i) < min.get(i) ) {
						if( closePrice.get(i) < min.get(i) ) {
							exitPrice = min.get(i) - 0.01;
							///**/System.out.println("first exit2");
							returnRate = exitPrice / entryPrice - 1.0;
							//canShowExitPrce = true;
							isSingleDayTrade = true;
							isEntry = false;
						}
					}
				}
				
				//3）凡是前面有连续true 的话， （就像SMW这样） 以下的就是在已经买入状态，所以不需要再次买入。所以只是检查是否达到exit 条件 

				//4）如果达到， 根据exit 条件来计算exit price 

				// 5） 然后 exit 后， 之后的日子（下个买入之前）都不需要检查时候有exit状态。 这个时候我们又回到 第一步。 
				//sample41之后添加了的 买入条件

	
			} else {
	
				//Exit (stop-loss): for each new day after entry:
				//-if (low <= SL) then: // check to see if stop-loss was hit on that day
					//-if (open > SL) then sell at SL // price opened higher, we were able to sell at target. 
					//-else sell at open // for gaps
				
				stopLossPrice = entryPrice - averageTrueRange(i) * 2;
				SL.set(i, stopLossPrice);
				
				if( lowPrice.get(i) <= SL.get(i) ) {
					//exitPrice = ( openPrice.get(i) > stopLossPrice ? stopLossPrice : openPrice.get(i));
					if( openPrice.get(i) > SL.get(i) ) {
						exitPrice = SL.get(i);
					} else {
						exitPrice = openPrice.get(i);
					}
					isEntry = false;
					///**/System.out.println("exit1");
					//returnRate = entryPrice - exitPrice;
					//entryPrice = 0.0;
					//returnRate = closePrice.get(i) / lastDayClosePrice - 1;
					
					//lastDayClosePrice = closePrice.get(i);
					//canShow = true;
					//continue;
				}
				else
				//Exit (target):
				//-if (low < 0.5*x-day low) then: // see if exit target was hit
					//-if (open > 0.5*x-day low) then sell at 0.5*x-day low-0.01 // no gap. (if low is 36.11, sell at 36.10 (adjusted for slippage/commission)) 
					//-else sell at open // gap
				if ( lowPrice.get(i) < min.get(i)) {
					if( openPrice.get(i) > min.get(i)) {
						exitPrice = min.get(i) - 0.01;
					} else {
						exitPrice = openPrice.get(i); 
					}
					isEntry = false;
					///**/System.out.println("exit2");
					//canShow = true;
					//entryPrice = 0.0;
				}
				

			}
		
		
			/* last = false */
			if( !lastIsEntry ) {
				// buy
				if( isEntry ) {
				/* current = true */
					canShowEntryPrice = true;
					canShowExitPrce = false; 
					canShowReturnRate = true;
					
					returnRate =  closePrice.get(i) / entryPrice - 1.0;
					
				// 判断   if （当天最低 < = SL)
				//   如果是， 判断 if (close price < SL), then exit price = SL - 0.01

				// 判断   if （当天最低 < 前x/2- day low)
				//   如果是， 判断 if (close < 前x/2- day low), then exit price = 前x/2- day low - 0.01

				} else {
				/* current = false */
					canShowEntryPrice = false;
					canShowExitPrce = false;
					canShowReturnRate = false;
					
					if(isSingleDayTrade) {
						
						canShowEntryPrice = true;
						canShowExitPrce = true;
						canShowReturnRate = true;		
						//returnRate = exitPrice / entryPrice - 1.0;
						///**/System.out.println("exitPrice: " + exitPrice + "\nentryPrice: " + entryPrice + "\nreturnRate: " + returnRate);
					}
					
					//returnRate = 0.0;
				}
				
			} else {
			/* last = true */
				// sell
				if(isEntry) {
				/* current = true */
					canShowEntryPrice = false;
					canShowExitPrce = false;
					canShowReturnRate = true;
					
					returnRate = closePrice.get(i) / lastDayClosePrice  - 1.0;
													
				} else {
				/* current = false */
					canShowEntryPrice = false;
					canShowExitPrce = true;
					canShowReturnRate = true;
				
					returnRate = exitPrice / lastDayClosePrice - 1.0;

				}
			
		}
		
			// output
/*
			System.out.println(
				dates.get(i) + "\t" 
				+ highPrice.get(i) + "\t"
				+ max.get(i) + "\t" 
				+ entryPrice + "\t"
				//+ exitPrice + "\t"
				//+ min.get(i) + "\t" 
				//+ closePrice.get(i) + "\t" 
				//+ trueRange(i, lastDayClosePrice) * 2 + "\t"
				+ ATR.get(i) * 2 + "\t"
				+ SL.get(i) + "\t"
				//+ (entryPrice != 0.0 ? true : false) + "\t"
				+ isEntry + "\t"
				+ "return"
				//+ openPrice.get(i) + "\t"
				//+ highPrice.get(i) + "\t" 
				//+ lowPrice.get(i)
			);
*/

			System.out.println(dates.get(i) + "\t" 
				+ SL.get(i) + "\t" 
				+ TR.get(i) + "\t" 
				+ ATR.get(i) + "\t" 
				+ (canShowEntryPrice ? entryPrice : 0.0) + "\t"
				+ (canShowExitPrce ? exitPrice : 0.0) + "\t"  
				+ highPrice.get(i) + "\t" 
				+ max.get(i) + "\t"
				+ lowPrice.get(i) + "\t"
				+ min.get(i) + "\t"
				+ isEntry + "\t"
				+ (canShowReturnRate ? returnRate : 0.0) + "\t"
				+ (isSingleDayTrade ? isSingleDayTrade : "no") + "\t"
				+ openPrice.get(i) + "\t"
				+ closePrice.get(i) + "\t"
				//+ lastDayClosePrice + "\t"
			);
			
			lastDayClosePrice = closePrice.get(i);
			lastIsEntry = isEntry;
			
			i++;
		}
	
	}
}
